/*-------------------------------------------------------------------------
 *
 * jsonapi.h
 *	  JSON API 支持的声明。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/common/jsonapi.h
 *
 *-------------------------------------------------------------------------
 */

#ifndef JSONAPI_H
#define JSONAPI_H

#include "lib/stringinfo.h"

typedef enum
{
	JSON_TOKEN_INVALID,
	JSON_TOKEN_STRING,
	JSON_TOKEN_NUMBER,
	JSON_TOKEN_OBJECT_START,
	JSON_TOKEN_OBJECT_END,
	JSON_TOKEN_ARRAY_START,
	JSON_TOKEN_ARRAY_END,
	JSON_TOKEN_COMMA,
	JSON_TOKEN_COLON,
	JSON_TOKEN_TRUE,
	JSON_TOKEN_FALSE,
	JSON_TOKEN_NULL,
	JSON_TOKEN_END
} JsonTokenType;

typedef enum
{
	JSON_SUCCESS,
	JSON_ESCAPING_INVALID,
	JSON_ESCAPING_REQUIRED,
	JSON_EXPECTED_ARRAY_FIRST,
	JSON_EXPECTED_ARRAY_NEXT,
	JSON_EXPECTED_COLON,
	JSON_EXPECTED_END,
	JSON_EXPECTED_JSON,
	JSON_EXPECTED_MORE,
	JSON_EXPECTED_OBJECT_FIRST,
	JSON_EXPECTED_OBJECT_NEXT,
	JSON_EXPECTED_STRING,
	JSON_INVALID_TOKEN,
	JSON_UNICODE_CODE_POINT_ZERO,
	JSON_UNICODE_ESCAPE_FORMAT,
	JSON_UNICODE_HIGH_ESCAPE,
	JSON_UNICODE_HIGH_SURROGATE,
	JSON_UNICODE_LOW_SURROGATE
} JsonParseErrorType;


/*
 * 该结构中的所有字段应视为只读。
 *
 * 如果 strval 不是 null，则它应包含词素的解转义值
 * 如果它是字符串。否则，这些字段名称大多是显而易见的。
 *
 * line_number 和 line_start 主要供解析器的
 * 错误报告例程使用。
 * token_terminator 和 prev_token_terminator 指向 token 结束后的字符，
 * 即，如果我们使用以 null 结尾的字符串，则在哪里会有一个 null 字节。
 */
typedef struct JsonLexContext
{
	char	   *input;
	int			input_length;
	int			input_encoding;
	char	   *token_start;
	char	   *token_terminator;
	char	   *prev_token_terminator;
	JsonTokenType token_type;
	int			lex_level;
	int			line_number;	/* 行号，从 1 开始 */
	char	   *line_start;		/* 该行在输入中的起始位置 */
	StringInfo	strval;
} JsonLexContext;

typedef void (*json_struct_action) (void *state);
typedef void (*json_ofield_action) (void *state, char *fname, bool isnull);
typedef void (*json_aelem_action) (void *state, bool isnull);
typedef void (*json_scalar_action) (void *state, char *token, JsonTokenType tokentype);


/*
 * 用于解析 json 的语义操作结构。
 * 这些操作中的任何一个都可以为 NULL，此时在该
 * 点什么也不做。同样，semstate 也可以为 NULL。
 * 使用一个全部为 NULL 的结构相当于进行一次纯解析而没有副作用，
 * 因此正是 json 输入例程所做的。
 *
 * 传递给这些操作的 'fname' 和 'token' 字符串为 palloc'd。
 * 解析器不会释放或进一步使用它们，因此
 * 操作函数可以自由使用它们。
 */
typedef struct JsonSemAction
{
	void	   *semstate;
	json_struct_action object_start;
	json_struct_action object_end;
	json_struct_action array_start;
	json_struct_action array_end;
	json_ofield_action object_field_start;
	json_ofield_action object_field_end;
	json_aelem_action array_element_start;
	json_aelem_action array_element_end;
	json_scalar_action scalar;
} JsonSemAction;

/*
 * pg_parse_json 将解析词法中的字符串，在
 * sem 中的适当位置调用操作函数。由它们决定在 semstate 中保持
 * 什么状态。如果它们需要访问词法分析器的状态，则其指针
 * 应作为 semstate 所指向的成员传递给它们。
 * 如果操作指针为 NULL，则解析器什么也不做，继续进行。
 */
extern JsonParseErrorType pg_parse_json(JsonLexContext *lex,
										JsonSemAction *sem);

/* 用于纯验证的空操作对象 */
extern PGDLLIMPORT JsonSemAction nullSemAction;

/*
 * json_count_array_elements 执行快速的二次解析以确定传入数组词法上下文中的元素数量。
 * 应从 array_start 操作中调用。
 *
 * 返回值指示是否发生任何错误，而元素的数量存储到 *elements 中
 * （仅当返回值为 JSON_SUCCESS 时）。
 */
extern JsonParseErrorType json_count_array_elements(JsonLexContext *lex,
													int *elements);

/*
 * JsonLexContext 的构造函数，有或没有 strval 元素。
 * 如果提供，strval 元素将包含词素的解转义版本。
 * 然而，执行此操作会带来性能损失，因此
 * 如果不需要解转义的词素，则应避免使用。
 */
extern JsonLexContext *makeJsonLexContextCstringLen(char *json,
													int len,
													int encoding,
													bool need_escapes);

/* 词法分析一个 token */
extern JsonParseErrorType json_lex(JsonLexContext *lex);

/* 为 json 错误构造错误详细信息字符串 */
extern char *json_errdetail(JsonParseErrorType error, JsonLexContext *lex);

/*
 * 实用程序函数，用于检查字符串是否为有效的 JSON 数字。
 *
 * str 参数不需要以 null 结束。
 */
extern bool IsValidJsonNumber(const char *str, int len);

#endif							/* JSONAPI_H */
